#include "Log.h"
#include <Sock.h>
#include <arpa/inet.h>
#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <asm-generic/socket.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>

namespace muduo{
    Socket::Socket():_sock(-1){}
    Socket::Socket(int sock):_sock(sock){}
    Socket::~Socket(){
        Close();
    }
    int Socket::Fd(){return _sock;}
    bool Socket::CreateSock(){
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if(_sock < 0) {
            errorlog << "create socket error";
            return false;
        }
        return true;
    }
    bool Socket::Bind(const std::string& ip, uint16_t port){
        struct sockaddr_in local;
        local.sin_family=AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = inet_addr(ip.c_str());
        if(bind(_sock,(struct sockaddr*)&local,sizeof(local))<0){
            errorlog << "socket bind error";
            return false;
        }
        return true;
    }
    bool Socket::Listen(int backlog=MAX_LISTEN){
        if(listen(_sock, backlog)<0){
            errorlog << "socket listen error";
            return false;
        }
        return true;
    }
    int Socket::Accept(){
        int sock = accept(_sock, nullptr, nullptr);
        if(sock < 0){
            errorlog << "accept error";
            return -1;
        }
        return sock;
    }
    bool Socket::Connect(const std::string& ip, uint16_t port){
        struct sockaddr_in server;
        server.sin_port=htons(port);
        server.sin_family=AF_INET;
        server.sin_addr.s_addr = inet_addr(ip.c_str());
        int tmp = connect(_sock, (struct sockaddr*)&server, sizeof(server));
        if(tmp < 0){
            errorlog << "connect error";
            return false;
        }
        return true;
    }
    ssize_t Socket::Recv(void *buf, size_t len, int flag){
        // 默认阻塞读取
        ssize_t ret = recv(_sock, buf, len, flag);
        if(ret <= 0 ){
            if((errno == EAGAIN) || (errno == EINTR) || (errno == EWOULDBLOCK)){
                return 0;
            }
            else{
                errorlog<<"recv error";
                return -1;
            }
        }
        return ret;
    }
    ssize_t Socket::Send(const void *buf, size_t len, int flag){
        // 默认阻塞发送
        ssize_t ret = send(_sock,buf,len,flag);
        if(ret <= 0 ){
            if((errno == EAGAIN) || (errno == EINTR) || (errno == EWOULDBLOCK))
                return 0;
            else{
                errorlog<<"send error";
                return -1;
            }
        }
        return ret;
    }
    ssize_t Socket::NonBlockRecv(void *buf, size_t len){
        return Recv(buf, len,MSG_DONTWAIT);
    }
    ssize_t Socket::NonBlockSend(void *buf, size_t len){
        return Send(buf, len,MSG_DONTWAIT);
    }
    bool Socket::CreateServer(uint16_t port,const std::string& ip,bool flag_block){
        // 1. 创建 2.设置非阻塞sock 3.绑定 4.监听 5.设置地址重用
        if(CreateSock()==false) return false;
        if(flag_block) SetNonBlock();
        if(Bind(ip, port)==false) return false;
        if(Listen()==false) return false;
        ReuseAddress();
        return true;
    }
    bool Socket::CreateClient(uint16_t port,const std::string& ip){
        if(CreateSock()==false) return false;
        if(Connect(ip,port)==false) return false;
        return true;
    }
    void Socket::Close(){
        if(_sock != -1)
            close(_sock);
        _sock = -1;
    }
    void Socket::ReuseAddress(){
        int val = 1;
        setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&val, sizeof(int));
        val =1;
        setsockopt(_sock, SOL_SOCKET, SO_REUSEPORT, (void*)&val, sizeof(int));
    }
    void Socket::SetNonBlock(){
        // 因为Sock状态有很多，所以我们不能直接覆盖，要先获取当前套接字状态
        int flag=fcntl(_sock,F_GETFL,0);
        fcntl(_sock, F_SETFL, flag | O_NONBLOCK);
    }
}